// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2005-4-29

#include "stdafx.h"
#include "module.h"
#include "strcrypt.h"

namespace JoyGuard
{

static LRESULT CALLBACK ModWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_CREATE:
        {
            CREATESTRUCT* cs = (CREATESTRUCT*)lParam;
            char* modName = (char*)cs->lpCreateParams;
            HMODULE hMod = GetModuleHandle(modName);
            memcpy(modName, &hMod, sizeof(hMod));
        }
        break;
    }
    return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}

static PCSTR ModGetClassName()
{
    static const char* clsName = "joyinter_common_control_wnd";

    WNDCLASS wc;
    ::memset(&wc, 0, sizeof(wc));
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = clsName;
    wc.lpfnWndProc = ModWindowProc;

    ::RegisterClass(&wc);

    return clsName;
}

//##ModelId=44C4B60D02FE
PROC Module::GetProc(HMODULE hMod, const char* cryptName)
{
    BYTE* baseAddr = (BYTE*)hMod;

    // get dos header
    IMAGE_DOS_HEADER* dosHeader    = (IMAGE_DOS_HEADER*)baseAddr;
    if(dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    {
        return NULL;
    }
    if(dosHeader->e_lfanew <= 0)
    {
        return NULL;
    }

    // get nt headers
    IMAGE_NT_HEADERS* headers   = (IMAGE_NT_HEADERS*)(baseAddr+dosHeader->e_lfanew);
    if(headers->Signature != IMAGE_NT_SIGNATURE)
    {
        return NULL;
    }

    // get export directory
    IMAGE_EXPORT_DIRECTORY* expDir = (IMAGE_EXPORT_DIRECTORY*)
        (baseAddr + headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    WORD wOrd = 0xFFFF;
    if((UINT_PTR)cryptName < 0xFFFF)
    {
        wOrd    = (WORD)(UINT_PTR)cryptName;
    }
    else
    {
        CHAR funcName[256];
        memset(funcName, 0, sizeof(funcName));
        StrCrypt::Decrypt(funcName, cryptName);

        DWORD dwNameNum = expDir->NumberOfNames;
        DWORD* pNameRva = (DWORD*)(baseAddr+expDir->AddressOfNames);
        for(unsigned i = 0; i < dwNameNum; i ++)
        {
            PCSTR pszProc = (PCSTR)(baseAddr+pNameRva[i]);
            if(strcmp(pszProc, funcName) == 0)
            {
                WORD* pNameOrd = (WORD*)(baseAddr+expDir->AddressOfNameOrdinals);
                wOrd = pNameOrd[i];
                break;
            }
        }
    }

    if(wOrd == 0xFFFF || wOrd >= expDir->NumberOfFunctions)
    {
        return NULL;
    }

    DWORD* pFuncRva = (DWORD*)(baseAddr + expDir->AddressOfFunctions);
    return (PROC)(baseAddr + pFuncRva[wOrd]);
}

//##ModelId=44C4B60D02F1
HMODULE Module::GetHandle(const char* cryptName)
{
    static const char* clsName = ModGetClassName();

    char modName[MAX_PATH];
    memset(modName, 0, sizeof(modName));
    StrCrypt::Decrypt(modName, cryptName);

    HWND hWnd = ::CreateWindow(clsName, "Edit", 0, 0, 0, 1, 1, NULL, NULL, GetModuleHandle(NULL), (LPVOID)modName);

    HMODULE hMod = *(HMODULE*)modName;
    memset(modName, 0, sizeof(modName));

    ::DestroyWindow(hWnd);

    return hMod;
}

} // namespace JoyGuard
